package middleware

import (
	"crypto/md5"
	"errors"
	"fmt"
	"net/http"
	"strings"
	"sync"
	"tosServer/internal/model"
	"tosServer/internal/pkg/cache"
	"tosServer/internal/pkg/db"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

var (
	mutex sync.RWMutex
)

func DavAuth(c *gin.Context) {
	username, pass, hasAuth := c.Request.BasicAuth()

	authFailed := func() {
		c.Header("WWW-Authenticate", `Basic realm="WebDAV"`)
		c.AbortWithStatus(http.StatusUnauthorized)
	}

	if username == "" || pass == "" || !hasAuth {
		authFailed()
		return
	}

	userCacheKey := fmt.Sprintf("%x", md5.Sum([]byte(username+pass)))
	mutex.RLock()
	davUserCache, ok := cache.C.Get(userCacheKey)
	mutex.RUnlock()
	var davUser model.DavUser
	if !ok {
		mutex.Lock()
		davUser = *new(model.DavUser)
		result := db.Db().Where(model.DavUser{
			Username: username,
		}).Preload("DavUserRole").First(&davUser)

		if errors.Is(result.Error, gorm.ErrRecordNotFound) || result.Error != nil {
			mutex.Unlock()
			authFailed()
			return
		}
		if !davUser.CheckPass(pass, davUser.Password, davUser.Salt) {
			mutex.Unlock()
			authFailed()
			return
		}
		cache.C.SetDefault(userCacheKey, davUser)
		mutex.Unlock()
	} else {
		davUser, ok = davUserCache.(model.DavUser)
		if !ok {
			authFailed()
			return
		}
	}

	c.Set("user", davUser)

	allow := true
	methods := davUser.DavUserRole.Methods
	if methods != "" {
		methods := strings.Split(methods, ",")
		for _, method := range methods {
			if method == c.Request.Method {
				allow = false
				break
			}

		}
	}

	if !allow {
		c.AbortWithStatus(http.StatusForbidden)
	}
}
